<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: YangPan <744600969@qq.com>
// +----------------------------------------------------------------------


// 应用公共文件
use think\Route;

Route::rule([## '404' => 'error/error_404', ##404错误页面
'test'=>'Index/test', 'sign_in'=>'Weixin/loginApplet', 'pub_upload_userinfo'=>'Weixin/updateUserinfo'] // 更新昵称 、头像、最后访问时间等信息
);

/**
 * 返回json格式数据后退出
 * @param array $data
 */
function ajaxReturn($data)
{
    header('Content-Type:application/json; charset=utf-8');
    echo json_encode($data);
    exit();
}

/**
 * 请求失败或者空数据是返回json数据
 * @param string    $info
 * @param array     $data
 * @param string    $code
 * @return json
 */
function err($info = 'error', $data = [], $code = 1)
{
    $datas = [];
    $datas['errcode'] = $code;
    
    if ( ! is_array($data)) {
        ajaxReturn(['error'=>'$data is not array']);
    }
    
    if ( ! empty($info)) {
        $datas['info'] = $info;
    }
    
    if ( ! empty($data)) {
        $datas['data'] = $data;
    }
    
    ajaxReturn($datas);
}

/**
 * 请求成功后返回json数据
 * @param string $info
 * @param array  $data
 * @return json
 */
function suc($info = 'success', $data = [], $code = 0)
{
    $datas = [];
    $datas['errcode'] = $code;
    
    if ( ! is_array($data)) {
        ajaxReturn(['error'=>'$data is not array']);
    }
    
    if ( ! empty($info)) {
        $datas['info'] = $info;
    }
    
    if ( ! empty($data)) {
        $datas['data'] = $data;
    }
    
    ajaxReturn($datas);
}

/**
 * 生成指定的随机字符串
 * @param int $length
 * @return string
 */
function getRandStr($length)
{
    $str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; //62个字符
    $strlen = 62;
    
    while ($length > $strlen) {
        $str .= $str;
        $strlen += 62;
    }
    
    $str = str_shuffle($str);
    return substr($str, 0, $length);
}

// 下载微信头像
function curlDowWxHead($url, $name)
{
    $ch = curl_init();
    $httpheader = array('Host'=>'mmbiz.qpic.cn', 'Connection'=>'keep-alive', 'Pragma'=>'no-cache', 'Cache-Control'=>'no-cache', 'Accept'=>'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8', 'User-Agent'=>'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.89 Safari/537.36', 'Accept-Encoding'=>'gzip, deflate, sdch', 'Accept-Language'=>'zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4');
    
    $options = array(CURLOPT_HTTPHEADER=>$httpheader, CURLOPT_URL=>$url, CURLOPT_TIMEOUT=>5, CURLOPT_FOLLOWLOCATION=>1, CURLOPT_RETURNTRANSFER=>true);
    curl_setopt_array($ch, $options);
    $result = curl_exec($ch);
    curl_close($ch);
    
    file_put_contents($name, $result);
    
    return true;
}

/**
 * 用curl处理get传值
 * @param string $url   链接url
 * @param string $data  传输的数据
 * @param string $type  数据类型：json/xml
 */
function curlGet($url, $type = '')
{
    if ($type == 'json') {
        $type = 'Content-Type:application/json;charset=utf-8';
    } elseif ($type == 'xml') {
        $type = 'Content-Type:text/xml;charset=utf-8';
    } else {
        $type = '';
    }
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30); // 只需要设置一个秒的数量就可以
    curl_setopt($ch, CURLOPT_HEADER, 0);
    
    //if (strlen($type) > 0) {
    //curl_setopt($ch, CURLOPT_HTTPHEADER, array($type, 'Content-Length:' . strlen($data)));
    //}
    

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    //返回结果
    if ($response) {
        return $response;
    } else {
        return curl_errno($ch);
    }
}

/**
 * 用curl处理post传值
 * @param string $url   链接url
 * @param string $data  传输的数据
 * @param string $type  数据类型：json/xml
 */
function curlPost($url, $data, $type = '')
{
    if ($type == 'json') {
        $type = 'Content-Type:application/json;charset=utf-8';
    } elseif ($type == 'xml') {
        $type = 'Content-Type:text/xml;charset=utf-8';
    } else {
        $type = '';
    }
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30); //只需要设置一个秒的数量就可以
    

    //if (strlen($type) > 0) {
    //curl_setopt($ch, CURLOPT_HTTPHEADER, array($type, 'Content-Length:' . strlen($data)));
    //}
    

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    //返回结果
    if ($response) {
        return $response;
    } else {
        return curl_errno($ch);
    }
}

/**
 * 阿拉伯数字转中文数字
 * @param num $month
 * @return string
 */
function getChineseNum($month)
{
    switch ($month) {
        case 1:
            $str_n = "一";
            break;
        case 2:
            $str_n = "二";
            break;
        case 3:
            $str_n = "三";
            break;
        case 4:
            $str_n = "四";
            break;
        case 5:
            $str_n = "五";
            break;
        case 6:
            $str_n = "六";
            break;
        case 7:
            $str_n = "七";
            break;
        case 8:
            $str_n = "八";
            break;
        case 9:
            $str_n = "九";
            break;
        case 10:
            $str_n = "十";
            break;
        case 11:
            $str_n = "十一";
            break;
        case 12:
            $str_n = "十二";
            break;
    }
    
    return $str_n;
}

/**
 * 入口验证
 * @param array $data
 * @param number $data['aid'] 客户id
 * @param number $data['uid'] 用户id
 * @param number $data['tid'] 时间戳
 * @param string $data['mid'] sha1(sing_key . uid . tid . aid)
 * @return boolean
 */
function sign($data)
{
    if ( ! is_numeric($data['uid']) or  ! is_numeric($data['aid']) or  ! is_numeric($data['tid']) or empty($data['mid'])) {
        return false;
    }
    
    $info = db('customer')->where(['id'=>$data['aid']])->field('id as admin_id, appid, secret, access_token')->find();
    
    if ( ! $info) {
        return false;
    }
    
    if ($data['mid'] != sha1($info['secret'] . $data['uid'] . $data['tid'] . $data['aid'])) {
        return false;
    }
    
    $info['aid'] = $data['aid'];
    $info['uid'] = $data['uid'];
    return $info;
}

/**
 * 入口解密处理 - 用于websoket
 * @param string $str
 * @return array
 */
function accessDecryptNoDb($str, $accessKey)
{
    if (strlen($str) < 120) {
        return false;
    }
    
    $md5str = substr($str,  - 32);
    $authstr = substr($str, 0, strlen($str) - 32);
    
    // 第一次解码
    if ($md5str != md5($authstr . $accessKey)) {
        return false;
    }
    
    // 第二次解码
    $arrAgain = str_split($authstr, 1);
    $str = '';
    foreach ($arrAgain as $key=>$val) {
        if ($key % 2 != 0) {
            $str .= $val;
        }
    }
    
    // 取值
    $uid = stristr($str, 'a', true);
    $string = stristr($str, 'a');
    $arr = str_split(substr($string, 1, 40), 4);
    $mid = $arr[1] . $arr[4] . $arr[2] . $arr[8] . $arr[9] . $arr[3] . $arr[6] . $arr[7] . $arr[5] . $arr[0];
    $tid = substr($string, 41, 10);
    $aid = substr($string, 51);
    
    $info['aid'] = $aid;
    $info['uid'] = $uid;
    $info['tid'] = $tid;
    return $info;
}

/**
 * 入口解密处理
 * @param string $str
 * @return array
 */
function accessDecrypt($str, $accessKey)
{
    if (strlen($str) < 120) {
        return false;
    }
    
    $md5str = substr($str,  - 32);
    $authstr = substr($str, 0, strlen($str) - 32);
    
    // 第一次解码
    if ($md5str != md5($authstr . $accessKey)) {
        return false;
    }
    
    // 第二次解码
    $arrAgain = str_split($authstr, 1);
    $str = '';
    foreach ($arrAgain as $key=>$val) {
        if ($key % 2 != 0) {
            $str .= $val;
        }
    }
    
    // 取值
    $uid = stristr($str, 'a', true);
    $string = stristr($str, 'a');
    $arr = str_split(substr($string, 1, 40), 4);
    $mid = $arr[1] . $arr[4] . $arr[2] . $arr[8] . $arr[9] . $arr[3] . $arr[6] . $arr[7] . $arr[5] . $arr[0];
    $tid = substr($string, 41, 10);
    $aid = substr($string, 51);
    
    $info = db('customer')->where(['id'=>$aid])->find();
    
    if ( ! $info) {
        return false;
    }
    
    if ($mid != sha1($info['secret'] . $uid . $tid . $aid)) {
        return false;
    }
    
    $info['aid'] = $aid;
    $info['uid'] = $uid;
    $info['tid'] = $tid;
    $info['admin_id'] = $info['id'];
    $info['audit'] = json_decode($info['audit']);
    return $info;
}

/**
 * 入口加密处理
 * @param number $aid
 * @param number $uid
 * @param number $tid
 * @param number $secret
 * @param string $accessKey
 * @return string
 */
function accessEncrypt($aid, $uid, $tid, $secret, $accessKey)
{
    $mid = sha1($secret . $uid . $tid . $aid);
    
    // 第一次打乱
    $arr = str_split($mid, 4);
    $mid = 'a' . $arr[9] . $arr[0] . $arr[2] . $arr[5] . $arr[1] . $arr[8] . $arr[6] . $arr[7] . $arr[3] . $arr[4];
    $str = $uid . $mid . $tid . $aid;
    
    // 第二次打乱，用md5加密打乱的数值一次
    $arr = str_split($str, 1);
    $string = '';
    foreach ($arr as $key=>$val) {
        $string .= rand(0, 9) . $val;
    }
    
    $string = $string . md5($string . $accessKey);
    return $string;
}

/**
 * 入口验证
 * @param string $action        方法名
 * @param array  $array         不需要验证的方法名
 */
function accessVerify($data)
{
    $string = strtolower($data['controller'] . '/' . $data['action']);
    
    // 不需要做入口验证
    if (in_array($string, $data['no_verify_func'])) {
        return true;
    }
    
    // 验证入口
    $accessData = accessDecrypt($data['mstr'], $data['access_key']);
    
    if ( ! $accessData) {
        err('ACCESS PARAM ERROR');
    }
    
    // 一天后过期 - 暂时验证日期
    //if (time() > $accessData['tid'] + 86400) {
    //err('TIMEOUT');
    //}
    

    return $accessData;
}

/**
 * 订单，商品，文章 - 参数解密 - 验证
 * @param array $data
 *      - sign_code     string      签名字符串
 *      - id            number      id
 *      - sign_key      string      签名KEY
 *      - sign_time     number      时间戳
 *       
 * @return json - err() or NULL
 */
function signDecrypt($data)
{
    if ($data['sign_code'] != sha1($data['id'] . $data['sign_key'] . $data['sign_time'])) {
        err('PARAM SIGN ERROR');
    }
}

/**
 * 参数加密
 * @param array $data
 * @return string
 */
function signEncrypt($data)
{
    return sha1($data['id'] . $data['sign_key'] . $data['sign_time']);
}

/**
 * 查询子树 - pid
 * @param array     $array  数据
 * @param number    $id     获取分类ID下的分类 - 0：父级，1：第二级，2：第三级
 * @return array
 */
function getCategoryList($array, $id)
{
    $ret = array();
    
    foreach ($array as &$addr) // 此处使用 & 运算符，提高效率
{
        if ($addr['pid'] == $id) {
            $addr['children'] = getCategoryList($array, $addr['id']);
            $ret[] = $addr;
        }
    }
    return $ret;
}

/**
 * 对查询结果集进行排序
 *
 * @param array  $list      查询结果
 * @param string $field     排序的字段名
 * @param array  $sortby    排序类型  - asc正向排序 desc逆向排序 nat自然排序
 * 
 * @return array
 */
function listSortBy(&$list, $field, $sortby = 'asc')
{
    if (is_array($list)) {
        $refer = $resultSet = array();
        foreach ($list as $i=>$data) {
            $refer[$i] = &$data[$field];
        }
        
        switch ($sortby) {
            case 'asc': // 正向排序
                asort($refer);
                break;
            case 'desc': // 逆向排序
                arsort($refer);
                break;
            case 'nat': // 自然排序
                natcasesort($refer);
                break;
        }
        
        foreach ($refer as $key=>$val) {
            $resultSet[] = &$list[$key];
        }
        
        $list = $resultSet;
        return true;
    }
    return false;
}

/**
 * 根据字符串键值对数据，返回数组(id=1&type=2 => ['id'=>1, 'type'=>2])
 * 
 * @param string $str
 * @return array
 */
function parseKeyVal($str)
{
    $param = explode('&', $str);
    $data = [];
    foreach ($param as $value) {
        $arr = explode('=', $value);
        $data[$arr[0]] = $arr[1];
    }
    
    return $data;
}

/**
 * 过滤昵称中的非法字符
 * 
 * @param string $nickname
 * @return string
 */
function removeEmoji($nickname)
{
    $clean_text = $nickname;
    
    // Match Emoticons
    $regexEmoticons = '/[\x{1F600}-\x{1F64F}]/u';
    $clean_text = preg_replace($regexEmoticons, '', $clean_text);
    
    // Match Miscellaneous Symbols and Pictographs
    $regexSymbols = '/[\x{1F300}-\x{1F5FF}]/u';
    $clean_text = preg_replace($regexSymbols, '', $clean_text);
    
    // Match Transport And Map Symbols
    $regexTransport = '/[\x{1F680}-\x{1F6FF}]/u';
    $clean_text = preg_replace($regexTransport, '', $clean_text);
    
    // Match Miscellaneous Symbols
    $regexMisc = '/[\x{2600}-\x{26FF}]/u';
    $clean_text = preg_replace($regexMisc, '', $clean_text);
    
    // Match Dingbats
    $regexDingbats = '/[\x{2700}-\x{27BF}]/u';
    $clean_text = preg_replace($regexDingbats, '', $clean_text);
    
    // 庆祝符
    $clean_text = preg_replace('/\xEE[\x80-\xBF][\x80-\xBF]|\xEF[\x81-\x83][\x80-\xBF]/', '', $clean_text);
    
    $clean_text = preg_replace('/\xE0[\x80-\x9F][\x80-\xBF]|\xED[\xA0-\xBF][\x80-\xBF]/', '', $clean_text);
    //$return = json_decode(preg_replace("#(\\\ud[0-9a-f]{3})#ie","",json_encode($clean_text)));
    

    return $clean_text;
}

/**
 * 后台入口验证
 * @param array     $data
 * @return boolean
 */
function adminVerify($data)
{
    // 不需要验证的方法
    if (in_array($data['action'], $data['no_verify_func'])) {
        return true;
    }
    
    $id = session('user_id');
    $auth = session('user_sign');
    
    if ($auth != md5($data['key'] . $id)) {
        return false;
    }
    
    return true;
}

/**
 * 验证身份证号
 * 
 * @param string  $vStr     身份证号码
 * @return bool
 */
function isCreditNo($vStr)
{
    $vCity = array('11', '12', '13', '14', '15', '21', '22', '23', '31', '32', '33', '34', '35', '36', '37', '41', '42', '43', '44', '45', '46', '50', '51', '52', '53', '54', '61', '62', '63', '64', '65', '71', '81', '82', '91');
    
    if ( ! preg_match('/^([\d]{17}[xX\d]|[\d]{15})$/', $vStr))
        return false;
    
    if ( ! in_array(substr($vStr, 0, 2), $vCity))
        return false;
    
    $vStr = preg_replace('/[xX]$/i', 'a', $vStr);
    $vLength = strlen($vStr);
    
    if ($vLength == 18) {
        $vBirthday = substr($vStr, 6, 4) . '-' . substr($vStr, 10, 2) . '-' . substr($vStr, 12, 2);
    } else {
        $vBirthday = '19' . substr($vStr, 6, 2) . '-' . substr($vStr, 8, 2) . '-' . substr($vStr, 10, 2);
    }
    
    if (date('Y-m-d', strtotime($vBirthday)) != $vBirthday)
        return false;
    if ($vLength == 18) {
        $vSum = 0;
        
        for ($i = 17; $i >= 0; $i -- ) {
            $vSubStr = substr($vStr, 17 - $i, 1);
            $vSum += (pow(2, $i) % 11) * (($vSubStr == 'a') ? 10: intval($vSubStr, 11));
        }
        
        if ($vSum % 11 != 1)
            return false;
    }
    
    return true;
}

/**
 * 验证手机号是否正确
 * 
 * @param number $mobile    手机号码
 * @return bool
 */
function isMobile($mobile)
{
    return preg_match("/^1[34578]{1}\d{9}$/", $mobile) ? true: false;
}

/**
 * 写入日志文件 - 用于测试
 * 
 * @param string    $mark   日志标记
 * @param array     $data   数据
 */
function logWriteInFile($mark = '', $data = [], $file = 'test.txt')
{
    $str = '';
    
    if ( ! empty($data)) {
        $str = json_encode($data);
    }
    
    $date = date('Y-m-d H:i:s');
    
    file_put_contents(ROOT_PATH . 'public' . DS . "uploads/$file", "[$date $mark]" . $str . PHP_EOL, FILE_APPEND);
}

/**
 * 日期、时间验证
 * @param unknown $date
 * @param string $format
 * @return boolean
 */
function validateDate($date, $format = 'Y-m-d H:i:s')
{
    $d = DateTime::createFromFormat($format, $date);
    return $d && $d->format($format) == $date;
}

/**
 * 地图 - 获取2点之间的距离 - 单位米
 * @param string $startLat       开始经度
 * @param string $startLng       开始纬度
 * @param string $endLat         结束经度
 * @param string $endLng         结束纬度
 *
 * @return string
 */
function getMapDistance($lat1, $lng1, $lat2, $lng2)
{
    $earthRadius = 6367000; //approximate radius of earth in meters
     
    /*
     Convert these degrees to radians
     to work with the formula
     */
     
    $lat1 = ($lat1 * pi() ) / 180;
    $lng1 = ($lng1 * pi() ) / 180;
     
    $lat2 = ($lat2 * pi() ) / 180;
    $lng2 = ($lng2 * pi() ) / 180;
     
    /*
     Using the
     Haversine formula
      
     http://en.wikipedia.org/wiki/Haversine_formula
      
     calculate the distance
     */
     
    $calcLongitude = $lng2 - $lng1;
    $calcLatitude = $lat2 - $lat1;
    $stepOne = pow(sin($calcLatitude / 2), 2) + cos($lat1) * cos($lat2) * pow(sin($calcLongitude / 2), 2);
    $stepTwo = 2 * asin(min(1, sqrt($stepOne)));
    $calculatedDistance = $earthRadius * $stepTwo;
     
    return round($calculatedDistance);
}